package template;

import java.io.File;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Properties;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;

public class Util {

	private static final Properties PROPERTIES = new Properties();
	private static boolean propertiesInitialized = false;
	private static final Object ELEMENT_PACKAGE_NAME = "Package";
	private static final Object ELEMENT_ASSEMBLY_NAME = "Assembly";
	private static final String ELEMENT_ENTITY_NAME = "Entity";
	private static final String ELEMENT_ENUMERATION_NAME = "Enumeration";
	private static final String ELEMENT_SERVICE_NAME = "Service";
	private static final Object ELEMENT_COMMENT_NAME = "Comment";
//	private static final Object ELEMENT_PRIMITIVETYPE_NAME = "PrimitiveType";
	private static final Object ELEMENT_ENTITY_SERVICE_NAME = "EntityService";

	public static String qualifiedName(EObject elem){
		return join(getCanonicalPath(elem), ".");
	}
	
	public static String packageName(EObject elem){
		LinkedList<String> canonicalPath = getCanonicalPath(elem);
		canonicalPath.removeLast();
		return join(canonicalPath, ".");
	}
	
	public static String packagePath(EObject elem){
		LinkedList<String> canonicalPath = getCanonicalPath(elem);
		canonicalPath.removeLast();
		return join(canonicalPath, File.separator);
	}
	
	public static EObject currentAssembly(EObject current){
		EObject result = null;
		do {
			if(ELEMENT_ASSEMBLY_NAME.equals(current.eClass().getName())){
				result = current;
			}
		}while( (current = current.eContainer())!=null);
		return result;
	}
	
	private static LinkedList<String> getCanonicalPath(EObject current){
		LinkedList<String> path = new LinkedList<String>();
		do {
			if(ELEMENT_PACKAGE_NAME.equals(current.eClass().getName())){
				path.add(current.eGet(current.eClass().getEStructuralFeature("name")).toString());
			}else if(ELEMENT_ASSEMBLY_NAME.equals(current.eClass().getName())){
				String namespace = current.eGet(current.eClass().getEStructuralFeature("namespace")).toString();
				String[] parts = namespace.split("\\.");
				for(int i=parts.length-1; i>=0; i--){
					path.add(parts[i]);
				}
			}else if(ELEMENT_ENTITY_NAME.equals(current.eClass().getName()) || ELEMENT_ENUMERATION_NAME.equals(current.eClass().getName()) || ELEMENT_SERVICE_NAME.equals(current.eClass().getName()) || ELEMENT_ENTITY_SERVICE_NAME.equals(current.eClass().getName())){
				path.add(current.eGet(current.eClass().getEStructuralFeature("name")).toString());			
			}
		}while( (current = current.eContainer())!=null);
		
		Collections.reverse(path);
		
		return path;
	}

	public EList<EObject> collectEntities(EObject assembly) {
		EList<EObject> entities = new BasicEList<EObject>();
		
		EList<EObject> childs = (EList<EObject>) assembly.eGet(assembly.eClass().getEStructuralFeature("elements"));
		for(EObject child : childs){
			if(ELEMENT_ENTITY_NAME.equals(child.eClass().getName())){
				entities.add(child);
			}else if(ELEMENT_PACKAGE_NAME.equals(child.eClass().getName())){
				entities.addAll(collectEntities(child));
			}
		}
		return entities;
	}
	
	public EList<EObject> collectServices(EObject assembly) {
		EList<EObject> services = new BasicEList<EObject>();
		
		EList<EObject> childs = (EList<EObject>) assembly.eGet(assembly.eClass().getEStructuralFeature("elements"));
		for(EObject child : childs){
			if(ELEMENT_SERVICE_NAME.equals(child.eClass().getName())){
				services.add(child);
			}else if(ELEMENT_PACKAGE_NAME.equals(child.eClass().getName())){
				services.addAll(collectServices(child));
			}
		}
		return services;
	}
	
	public static String getProperty(EObject obj, String key) throws Exception{
		if(!propertiesInitialized){
			PROPERTIES.load(Util.class.getClassLoader().getResourceAsStream("workflow/generator.properties"));
			propertiesInitialized = false;
		}
		if(!PROPERTIES.containsKey(key)){
			throw new IllegalStateException("Property Key "+key+" unknown");
		}
		return PROPERTIES.getProperty(key, key);
	}
	
	public static String formatComment(EObject obj, String prefix){
		StringBuilder comments = new StringBuilder();
		if(ELEMENT_ENTITY_NAME.equals(obj.eClass().getName())){
			for(EObject child : obj.eContents()){
				if(ELEMENT_COMMENT_NAME.equals(child.eClass().getName())){
					comments.append(prefix);
					comments.append(child.eGet(child.eClass().getEStructuralFeature("body")).toString());
					comments.append("\n");
				}
			}
		}
		return comments.length()>0 ? comments.toString().replaceAll("\\n", (new StringBuilder()).append("\n").append(prefix).toString()) : "";
	}
	
	private static String join(Iterable<String> s, String delimiter) {
	    if (s == null) return "";
	    Iterator<String> iter = s.iterator();
	    StringBuilder builder = new StringBuilder(iter.next());
	    while( iter.hasNext() ){
	        builder.append(delimiter).append(iter.next());
	    }
	    return builder.toString();
	}
	
}
